/**
 * @file   AbstractNode.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2014-04-28
 * @brief  Base class for a DON node.
 *
 * Copyright 2014  Djuro Drljaca (djurodrljaca@gmail.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DON/Core/Node/AbstractNode.h>
#include <DON/Core/Packet/PacketParser.h>
#include <QtCore/QString>

using namespace DON::Core::Node;
using namespace DON::Core::Packet;

class AbstractNode::Private
{
public:
    Private()
        : networkAddress(0u),
          networkAddressCount(0u),
          name(),
          type(),
          communicationMode(CommunicationMode_Invalid),
          maxPayloadLength(0u),
          nextSequence(0u),
          packetParser()
    { }

    quint16 networkAddress;
    quint16 networkAddressCount;
    QString name;
    QString type;
    CommunicationMode communicationMode;
    quint16 maxPayloadLength;
    quint16 nextSequence;
    PacketParser packetParser;
};

AbstractNode::AbstractNode()
    : d(new Private())
{
}

AbstractNode::~AbstractNode()
{
    delete d;
}

bool AbstractNode::isValid() const
{
    bool valid = false;

    if (d->networkAddressCount > 0)
    {
        const int address = static_cast<int>(d->networkAddress);
        const int addressCount = static_cast<int>(d->networkAddressCount);

        if ((address + addressCount) <= (1 << 16))
        {
            valid = true;
        }
    }

    if (valid)
    {
        valid = isCommunicationModeValid(d->communicationMode);
    }

    if (valid)
    {
        if (d->maxPayloadLength == 0)
        {
            valid = false;
        }
    }

    return valid;
}

quint16 AbstractNode::getNetworkAddress() const
{
    return d->networkAddress;
}

quint16 AbstractNode::getNetworkAddressCount() const
{
    return d->networkAddressCount;
}

void AbstractNode::setNetworkAddress(const quint16 networkAddress)
{
    d->networkAddress = networkAddress;
    d->networkAddressCount = 1u;
}

void AbstractNode::setNetworkAddressRange(const quint16 networkAddress,
                                          const quint16 networkAddressCount)
{
    d->networkAddress = networkAddress;
    d->networkAddressCount = networkAddressCount;
}

QString AbstractNode::getName() const
{
    return d->name;
}

void AbstractNode::setName(const QString &name)
{
    d->name = name;
}

QString AbstractNode::getType() const
{
    return d->type;
}

void AbstractNode::setType(const QString &type)
{
    d->type = type;
}

CommunicationMode AbstractNode::getCommunicationMode() const
{
    return d->communicationMode;
}

void AbstractNode::setCommunicationMode(const CommunicationMode communicationMode)
{
    d->communicationMode = communicationMode;
}

quint16 AbstractNode::getMaxPayloadLength() const
{
    return d->maxPayloadLength;
}

void AbstractNode::setMaxPayloadLength(const quint16 maxPayloadLength)
{
    d->maxPayloadLength = maxPayloadLength;
}

quint16 AbstractNode::getNextSequence()
{
    const quint16 nextSequence = d->nextSequence;

    d->nextSequence++;

    return nextSequence;
}

bool AbstractNode::sendPacket(const Packet::AbstractPacket &packet)
{
    const QByteArray data = packet.toBinary();
    bool success = false;

    if (data.isEmpty() == false)
    {
        success = sendData(data);
    }

    return success;
}

void AbstractNode::handleReceivedPacket(const GenericPacket &)
{
    // Just discard the data
}

void AbstractNode::addReceivedData(const QByteArray &receivedData)
{
    d->packetParser.addData(receivedData);
}

void AbstractNode::processReceivedData()
{
    d->packetParser.parseData();
    bool success = true;

    while (success &&
           d->packetParser.packetsAvailable())
    {
        const GenericPacket packet = d->packetParser.takePacket(&success);

        if (success)
        {
            handleReceivedPacket(packet);
        }
    }
}

bool AbstractNode::sendData(const QByteArray &)
{
    // Just discard the data
    return false;
}
